package com.shijie.component;

import java.io.BufferedReader;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONObject;
import com.shijie.core.annotation.Log;
import com.shijie.core.constants.PnConstant.OperatorType;
import com.shijie.domain.entity.Logs;
import com.shijie.service.LogsService;
import com.shijie.utils.CommonUtil;
import com.shijie.utils.HttpUtil;

@Aspect
@Component
@EnableAsync
public class LogAspect {
	private static final Logger log = LoggerFactory.getLogger(LogAspect.class);

	public static final String IP_URL = "http://ip.taobao.com/service/getIpInfo.php";

	@Autowired
	private LogsService logsService;
	@Autowired
	private ErpUserService erpUserService;
	@Autowired
	private AppUserService appUserService;

	// 配置织入点
	@Pointcut("@annotation(com.shijie.core.annotation.Log)")
	public void logPointCut() {
	}

	/**
	 * 前置通知 用于拦截操作
	 *
	 * @param joinPoint
	 *            切点
	 */
	@AfterReturning(pointcut = "logPointCut()")
	public void doBefore(JoinPoint joinPoint) {
		handleLog(joinPoint, null);
	}

	/**
	 * 拦截异常操作
	 * 
	 * @param joinPoint
	 * @param e
	 */
	@AfterThrowing(value = "logPointCut()", throwing = "e")
	public void doAfter(JoinPoint joinPoint, Exception e) {
		handleLog(joinPoint, e);
	}

	@Async
	protected void handleLog(final JoinPoint joinPoint, final Exception e) {
		try {
			// 获得注解
			HttpServletRequest request = CommonUtil.getRequest();
			Log controllerLog = getAnnotationLog(joinPoint);
			if (controllerLog == null) {
				return;
			}
			// 获取当前的用户
			Integer userId = null;
			String userName = null;
			if (OperatorType.ERP.equals(controllerLog.channel())) {
				userId = erpUserService.getUserId();
				userName = erpUserService.getUserName();
			} else if (OperatorType.MOBILE.equals(controllerLog.channel())) {
				userId = appUserService.getCurrentUser().getId();
				userName = appUserService.getUserName();
			}
			Logs operLog = new Logs();
			operLog.setStatus("success");
			operLog.setUserId(userId);
			operLog.setUserName(userName);
			// 请求的地址
			operLog.setIp(getIpAddr(request));
			// 操作地点
			//operLog.setLocation(getRealAddressByIP(operLog.getIp()));
			operLog.setOperUrl(request.getRequestURI());
			// 设置方法名称
			String className = joinPoint.getTarget().getClass().getName();
			String methodName = joinPoint.getSignature().getName();
			operLog.setMethod(className + "." + methodName + "()");
			// 处理设置注解上的参数
			getControllerMethodDescription(controllerLog, operLog,request);
			if (e != null) {
				operLog.setStatus("fail");
				operLog.setVisitResult(e.getMessage());
			}
			logsService.save(operLog);
		} catch (Exception exp) {
			log.error("==前置通知异常==");
			log.error("异常信息:{}", exp.getMessage());
		}
	}

	public void getControllerMethodDescription(Log log, Logs operLog,HttpServletRequest request)
			throws Exception {
		// 设置action动作
		operLog.setAction(log.action());
		// 设置标题
		operLog.setTitle(log.title());
		// 设置channel
		operLog.setChannel(log.channel());
		// 是否需要保存request，参数和值
		if (log.isSaveRequestData()) {
			// 获取参数的信息，传入到数据库中。
			setRequestValue(operLog,request);
		}
	}

	private void setRequestValue(Logs operLog,HttpServletRequest request) {
		Map<String, String[]> map = request.getParameterMap();
		String params = JSONObject.toJSONString(map);
		operLog.setOperParams(params);
		operLog.setOperUrl(request.getRequestURI());
	}

	/**
	 * 是否存在注解，如果存在就获取
	 */
	private Log getAnnotationLog(JoinPoint joinPoint) throws Exception {
		Signature signature = joinPoint.getSignature();
		MethodSignature methodSignature = (MethodSignature) signature;
		Method method = methodSignature.getMethod();

		if (method != null) {
			return method.getAnnotation(Log.class);
		}
		return null;
	}

	private String getIpAddr(HttpServletRequest request) {
		String ip = request.getHeader("x-forwarded-for");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		return ip;
	}

	public static String getRealAddressByIP(String ip) {
		String address = "";
		try {
			address = HttpUtil.sendPost(IP_URL, "ip=" + ip);
			JSONObject json = JSONObject.parseObject(address);
			JSONObject object = json.getObject("data", JSONObject.class);
			String region = object.getString("region");
			String city = object.getString("city");
			address = region + " " + city;
		} catch (Exception e) {
			log.error("根据IP获取所在位置----------错误消息：" + e.getMessage());
		}
		return address;
	}
}
